/**
* File: War3Source_Element.sp
* Description: The Element race for SourceCraft.
* Author(s): xDr.HaaaaaaaXx 
*/

#pragma semicolon 1
#include <sourcemod>
#include <sdktools_tempents>
#include <sdktools_functions>
#include <sdktools_tempents_stocks>
#include <sdktools_entinput>
#include <sdktools_sound>
#include <haaaxfunctions>

//#include "W3SIncs/War3Source_Interface"

// War3Source stuff
new thisRaceID, SKILL_ATTACK, SKILL_SPEED, SKILL_TIME, ULT_PUSH;

// Chance/Data Arrays
new Float:ImpulseChance[6] = { 0.0, 0.13, 0.18, 0.23, 0.27, 0.30 };
new Float:TimeChance[6] = { 0.0, 0.20, 0.25, 0.27, 0.28, 0.36 };
new Float:ElementSpeed[6] = { 0.0, 1.2, 1.25, 1.3, 1.35, 1.4 };
new Float:TimeDelay[6] = { 0.0, 2.0, 3.0, 5.0, 7.0, 8.0 };
new ImpulseDamage[6] = { 0, 4, 5, 6, 8, 11 };
new GravForce[6] = { 0, 1, 2, 3, 4, 5 };
new Float:AttackerPos[64][3];
new Float:FlyDuration = 5.0;
new Float:ClientPos[64][3];

// Sounds
new String:citadelsound[] = "ambient/levels/citadel/weapon_disintegrate3.wav";
new String:sound1[] = "weapons/physcannon/physcannon_pickup.wav";
new String:spawn[] = "weapons/physcannon/superphys_launch2.wav";
new String:sound2[] = "weapons/physcannon/energy_bounce1.wav";
new String:death[] = "weapons/physcannon/physcannon_drop.wav";
new String:spawn1[] = "ambient/machines/machine1_hit1.wav";
new String:spawn2[] = "weapons/irifle/irifle_fire2.wav";

// Other
new HaloSprite, AttackSprite1, AttackSprite2;
new m_vecBaseVelocity, m_hMyWeapons;
new Float:LastTimeUsed[64];

public Plugin:myinfo = 
{
	name = "War3Source Race - Element",
	author = "xDr.HaaaaaaaXx",
	description = "The Element race for War3Source.",
	version = "1.0.0.0",
	url = ""
};

public OnPluginStart()
{
	m_vecBaseVelocity = FindSendPropOffs( "CBasePlayer", "m_vecBaseVelocity" );
	m_hMyWeapons = FindSendPropOffs( "CBaseCombatCharacter", "m_hMyWeapons" );
	HookEvent( "player_death", PlayerDeathEvent );
}

public OnWar3PlayerAuthed( client )
{
	LastTimeUsed[client] = 0.0;
}

public OnMapStart()
{
	War3_PrecacheSound( citadelsound );
	War3_PrecacheSound( sound1 );
	War3_PrecacheSound( spawn );
	War3_PrecacheSound( sound2 );
	War3_PrecacheSound( death );
	War3_PrecacheSound( spawn1 );
	War3_PrecacheSound( spawn2 );
	HaloSprite = PrecacheModel( "materials/sprites/halo01.vmt" );
	AttackSprite1 = PrecacheModel( "materials/sprites/purplelaser1.vmt" );
	AttackSprite2 = PrecacheModel( "materials/sprites/glow.vmt" );
}

public OnWar3PluginReady()
{
	thisRaceID = War3_CreateNewRace( "Element", "element" );
	
	SKILL_ATTACK = War3_AddRaceSkill( thisRaceID, "Impulse Rifle", "Do more Damage and Disentegrate the enemie", false, 5 );	
	SKILL_SPEED = War3_AddRaceSkill( thisRaceID, "Transport", "Go a little faster", false, 5 );	
	SKILL_TIME = War3_AddRaceSkill( thisRaceID, "Times Element", "Go back to the exact moment before death", false, 5 );
	ULT_PUSH = War3_AddRaceSkill( thisRaceID, "Gravity Gun", "Pull the enemy player torward you", true, 5 );
	
	W3SkillCooldownOnSpawn( thisRaceID, ULT_PUSH, 5.0 );
	
	War3_CreateRaceEnd( thisRaceID );
}

public InitPassiveSkills( client )
{
	if( War3_GetRace( client ) == thisRaceID )
	{
		War3_SetBuff( client, fMaxSpeed, thisRaceID, ElementSpeed[War3_GetSkillLevel( client, thisRaceID, SKILL_SPEED )] );
		W3SetPlayerColor( client, thisRaceID, 120, 120, 120, _, GLOW_DEFAULT );
	}
}

public OnRaceChange( client, oldrace, newrace )
{
	if( newrace != thisRaceID )
	{
		War3_SetBuff( client, fMaxSpeed, thisRaceID, 1.0 );
		W3ResetAllBuffRace( client, thisRaceID );
	}
	else
	{	
		if( IsPlayerAlive( client ) )
		{
			InitPassiveSkills( client );
		}
	}
}

public OnSkillLevelChanged( client, race, skill, newskilllevel )
{
	InitPassiveSkills( client );
}

public OnWar3EventSpawn( client )
{
	new race = War3_GetRace( client );
	if( race == thisRaceID )
	{
		InitPassiveSkills( client );
		EmitSoundToAll( spawn1, client );
		EmitSoundToAll( spawn2, client );
	}
	else
	{
		W3ResetPlayerColor( client, thisRaceID );
	}
}

public OnWar3EventPostHurt( victim, attacker, damage )
{
	if( W3GetDamageIsBullet() && ValidPlayer( victim, true ) && ValidPlayer( attacker, true ) && GetClientTeam( victim ) != GetClientTeam( attacker ) )
	{
		if( War3_GetRace( attacker ) == thisRaceID )
		{
			new skill_level = War3_GetSkillLevel( attacker, thisRaceID, SKILL_ATTACK );
			if( !Hexed( attacker, false ) && GetRandomFloat( 0.0, 1.0 ) <= ImpulseChance[skill_level] )
			{
				War3_DealDamage( victim, ImpulseDamage[skill_level], attacker, DMG_BULLET, "element_crit" );
				
				W3PrintSkillDmgHintConsole( victim, attacker, War3_GetWar3DamageDealt(), SKILL_ATTACK );
				
				new Float:StartPos[3];
				new Float:EndPos[3];
				
				GetClientAbsOrigin( attacker, StartPos );
				GetClientAbsOrigin( victim, EndPos );
				
				StartPos[2] += 40;
				EndPos[2] += 40;
				
				TE_SetupBeamPoints( StartPos, EndPos, AttackSprite1, HaloSprite, 0, 1, 0.5, 0.5, 0.5, 0, 0.0, { 254, 254, 254, 255 }, 1 );
				TE_SendToAll();
				
				TE_SetupBeamPoints( StartPos, EndPos, AttackSprite1, HaloSprite, 0, 1, 0.5, 0.5, 0.5, 0, 0.0, { 254, 254, 254, 255 }, 1 );
				TE_SendToAll();
				
				TE_SetupBeamPoints( StartPos, EndPos, AttackSprite2, HaloSprite, 0, 1, 0.5, 2.5, 2.5, 0, 0.0, { 254, 254, 254, 255 }, 1 );
				TE_SendToAll();

				TE_SetupBeamPoints( StartPos, EndPos, AttackSprite2, HaloSprite, 0, 1, 0.5, 2.5, 2.5, 0, 0.0, { 254, 254, 254, 254 }, 1 );
				TE_SendToAll();
				
				EmitSoundToAll( citadelsound, victim );
				EmitSoundToAll( citadelsound, attacker );
			}
		}
	}
}

public OnUltimateCommand( client, race, bool:pressed )
{
	if( race == thisRaceID && pressed && IsPlayerAlive( client ) && !Silenced( client ) )
	{
		new ult_level = War3_GetSkillLevel( client, race, ULT_PUSH );
		if( ult_level > 0 )
		{
			if( War3_SkillNotInCooldown( client, thisRaceID, ULT_PUSH, true ) )
			{
				Push( client );
			}
		}
		else
		{
			W3MsgUltNotLeveled( client );
		}
	}
}

stock Push( client )
{
	new ult_level = War3_GetSkillLevel( client, thisRaceID, ULT_PUSH );
	new target;
	
	if( GetClientTeam( client ) == TEAM_T )
		target = War3_GetRandomPlayer( "#ct", true, true );
	if( GetClientTeam( client ) == TEAM_CT )
		target = War3_GetRandomPlayer( "#t", true, true );
	
	if( target == 0 )
	{
		PrintHintText( client, "No Target Found" );
	}
	else
	{
		new Float:pos1[3];
		new Float:pos2[3];
		
		GetClientAbsOrigin( client, pos1 );
		GetClientAbsOrigin( target, pos2 );
		
		new Float:localvector[3];
		
		localvector[0] = pos1[0] - pos2[0];
		localvector[1] = pos1[1] - pos2[1];
		localvector[2] = pos1[2] - pos2[2];

		new Float:velocity1[3];
		new Float:velocity2[3];
		
		velocity1[0] += 0;
		velocity1[1] += 0;
		velocity1[2] += 300;
		
		velocity2[0] = localvector[0] * ( 100 * GravForce[ult_level] );
		velocity2[1] = localvector[1] * ( 100 * GravForce[ult_level] );
		velocity2[2] = localvector[2] * ( 100 * GravForce[ult_level] );
		
		SetEntDataVector( target, m_vecBaseVelocity, velocity1, true );
		SetEntDataVector( target, m_vecBaseVelocity, velocity2, true );
		
		EmitSoundToAll( sound1, client );
		EmitSoundToAll( sound1, target );
		
		EmitSoundToAll( sound2, client );
		EmitSoundToAll( sound2, target );
		
		War3_SetBuff( target, bFlyMode, thisRaceID, true );
		War3_DealDamage( target, 1, client, DMG_BULLET, "element_crit" );
		CreateTimer( FlyDuration, StopFly, target );
		
		new String:NameAttacker[64];
		GetClientName( client, NameAttacker, 64 );
		
		new String:NameVictim[64];
		GetClientName( target, NameVictim, 64 );
		
		PrintToChat( client, "\x05: \x03You have pulled \x04%s \x03closer to you", NameVictim );
		PrintToChat( target, "\x05: \x03You have been pulled torward \x04%s", NameAttacker );
		
		War3_CooldownMGR( client, 20.0, thisRaceID, ULT_PUSH );
	}
}

public Action:StopFly( Handle:timer, any:client )
{
	if( ValidPlayer( client, true ) )
	{
		War3_SetBuff( client, bFlyMode, thisRaceID, false );
	}
}

public PlayerDeathEvent( Handle:event, const String:name[], bool:dontBroadcast )
{
	new client = GetClientOfUserId( GetEventInt( event, "userid" ) );
	new attacker = GetClientOfUserId( GetEventInt( event, "attacker" ) );
	if( War3_GetRace( client ) == thisRaceID && attacker != client && attacker != 0 )
	{
		new skill_time = War3_GetSkillLevel( client, thisRaceID, SKILL_TIME );
		if( skill_time > 0 && GetRandomFloat( 0.0, 1.0 ) <= TimeChance[skill_time] && LastTimeUsed[client] < GetGameTime() - ( TimeDelay[skill_time] + 15.0 ) )
		{
			LastTimeUsed[client] = GetGameTime();
			
			GetClientAbsOrigin( client, ClientPos[client] );
			GetClientAbsOrigin( attacker, AttackerPos[attacker] );
			
			CreateTimer( TimeDelay[skill_time], SpawnClient, client );
			CreateTimer( TimeDelay[skill_time], SpawnAttacker, attacker );
			
			PrintToChat( client, "\x05: \x03In \x04%f \x03seconds \x04Time's Element \x03will peice together your last Moment", TimeDelay[skill_time] );
			PrintToChat( attacker, "\x05: \x03In \x04%f \x03seconds you go back in time to this verry moment", TimeDelay[skill_time] );
			
			EmitSoundToAll( death, client );
			EmitSoundToAll( death, attacker );
		}
	}
}

public Action:SpawnClient( Handle:timer, any:client )
{
	if( ValidPlayer( client, false ) )
	{
		War3_SpawnPlayer( client );
		
		CreateTimer( 0.2, TeleportClient, client );
	}
}

public Action:SpawnAttacker( Handle:timer, any:client )
{
	if( ValidPlayer( client, false ) )
	{
		War3_SpawnPlayer( client );
		
		CreateTimer( 0.2, TeleportAttacker, client );
	}
}

public Action:TeleportClient( Handle:timer, any:client )
{
	if( ValidPlayer( client, true ) )
	{
		new Float:ang[3];
		
		War3_CachedAngle( client, ang );
		
		TeleportEntity( client, ClientPos[client], ang, NULL_VECTOR );
		
		EmitSoundToAll( spawn, client );
		
		CreateTimer( 0.1, GivePlayerCachedDeathWPNFull, client );
	}
}

public Action:TeleportAttacker( Handle:timer, any:client )
{
	if( ValidPlayer( client, true ) )
	{
		new Float:ang[3];
		
		War3_CachedAngle( client, ang );
		
		TeleportEntity( client, AttackerPos[client], ang, NULL_VECTOR );
		
		EmitSoundToAll( spawn, client );
		
		CreateTimer( 0.1, GivePlayerCachedDeathWPNFull, client );
	}
}

public Action:GivePlayerCachedDeathWPNFull( Handle:h, any:client )
{
	if( ValidPlayer( client, true ) )
	{
		for( new s = 0; s < 10; s++ )
		{
			new ent = GetEntDataEnt2( client, m_hMyWeapons + ( s * 4 ) );
			if( ent > 0 && IsValidEdict( ent ) )
			{
				new String:ename[64];
				GetEdictClassname( ent, ename, sizeof( ename ) );
				if( StrEqual( ename, "weapon_c4" ) || StrEqual( ename, "weapon_knife" ) )
				{
					continue;
				}
				UTIL_Remove( ent );
			}
		}
		for( new s = 0; s < 10; s++ )
		{
			new String:wep_check[64];
			War3_CachedDeadWeaponName( client, s, wep_check, sizeof( wep_check ) );
			if( !StrEqual( wep_check, "" ) && !StrEqual( wep_check, "", false ) && !StrEqual( wep_check, "weapon_c4" ) && !StrEqual( wep_check, "weapon_knife" ) )
			{
				GivePlayerItem( client, wep_check );
			}
		}
		War3_SetCSArmor( client, 100 );
		War3_SetCSArmorHasHelmet( client, true );
	}
}